#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<stdlib.h>//getenv()

//int main(int argc,char* argv[],char* env[])//env存放的就是系统环境变量的内容
//{
//    int i = 0;
//    for(; env[i]; i++)//因为env和argv数组最后一个元素就是NULL，所以只要为空就终止循环
//    {
//       printf("pid: %d, env[%d]: %s\n", getpid(), i, env[i]);
//    }
//    
//    return 0;
//}


////不使用命令行参数获取环境变量的方法
//int main()
//{
//   
//    //extern char** environ;//这个指针就指向了环境变量表，也就是上面的char* env[]，所以是二级指针
//    //int i = 0;
//    //for(; environ[i]; i++)
//    //{
//    //   printf("%d: %s\n",i,environ[i]);
//    //}
//
//    //pid_t id = fork();
//    //if(id == 0)//这段代码说明了所有子进程（包括孙子进程）也可以继承bash环境变量表的内容，即全局性
//    //{       
//    //   extern char** environ;//这个指针就指向了环境变量表，也就是上面的char* env[]，所以是二级指针
//    //   int i = 0;
//    //   for(; environ[i]; i++)
//    //   {
//    //      printf("%d: %s\n",i,environ[i]);
//    //   }
//    //}
//    
//    printf("OUR_ENV: %s\n", getenv("OUR_ENV"));//要先"export OUR_ENV=1000"才可以查得到，注意export后面是一个整体，不可以有空格
//
//    return 0;
//}


////查看程序地址空间
//int un_gval;
//int init_gval = 100;
//struct s{
//    int a;
//    int b;
//    int c;
//}obj;
//
//int main(int argc,char* argv[],char* env[])
//{
//    printf("代码区：%p\n", main);
//    
//    const char* str = "hello linux";//str其实是个位于栈区的局部变量
//    printf("字符常量区：%p\n",str);//不需要加&，因为str的内容就是字符串首元素的地址
//
//    //char* str1 = "hello";
//    //*str1 = 'H';//不可以修改字符串的内容，因为代码区只读而不可修改，字符常量区和代码区挨在一起也是不可修改的
//    ////str = "H"是对的，这只是把指针指向了新的字符串
//
//    printf("已初始化全局数据区：%p\n",&init_gval);
//    
//    printf("未初始化全局数据区：%p\n",&un_gval);
//
//    char* heap = (char*)malloc(100);//开辟的空间在堆区，但是heap1在栈区，只不过它的内容指向了堆区
//    printf("堆区：%p\n",heap);
//
//    printf("栈区：%p\n",&str);//注意这里要加&
//
//    printf("\n");
//
//    //验证堆区向上增长，栈区向下增长（堆栈相对而生）--向上是高地址 
//    char* heap1 = (char*)malloc(100);
//    char* heap2 = (char*)malloc(100);
//    char* heap3 = (char*)malloc(100);
//    char* heap4 = (char*)malloc(100);
//    static int a = 0;//不加static就是在栈区上开辟空间，加了static之后本质上a存放于静态区（也是在已初始化全局数据区）
//    //也就是说被static修饰的变量本质上已经是全局变量了
//
//    printf("堆区1：%p\n",heap1);
//    printf("堆区2：%p\n",heap2);
//    printf("堆区3：%p\n",heap3);
//    printf("堆区4：%p\n",heap4);
//
//
//    printf("栈区：%p\n",&str);//注意这里要加&
//    printf("栈区：%p\n",&heap1);
//    printf("栈区：%p\n",&heap2);
//    printf("栈区：%p\n",&heap3);
//    printf("栈区：%p\n",&heap4);
//    printf("栈区：%p\n",&a);
//    
//    printf("\n");
//
//    //验证结构体成员的地址
//    printf("%p\n",&obj);
//    printf("%p\n",&obj.a);
//    printf("%p\n",&obj.b);
//    printf("%p\n",&obj.c);
//    
//    //栈区之上是命令行参数的地址，再往上是环境变量的地址
//    int i = 0;
//    for(; argv[i]; i++)
//    {
//        printf("argv[%d]: %p\n", i, argv[i]);//不用加&，因为这是指针数组
//    }
//    for(i = 0; env[i]; i++)
//    {
//        printf("env[%d]: %p\n", i, env[i]);
//    }
//
//
//    return 0;
//
//}


//不同的进程之间的数据是各自保存一份的，但是在打印地址的时候居然发现下面两个进程中的g_val变量地址一样，对应的值却不相同
int g_val = 100;
int main()
{
    pid_t id = fork();
    if(id == 0)
    {
       //child
       int cnt = 5;
       while(1)
       {
           printf("child, Pid: %d, Ppid: %d, g_val: %d, &g_val=%p\n",getpid(),getppid(),g_val,&g_val);
           sleep(1);
           if(cnt == 0)
           {
              g_val = 200;
              printf("child change g_val:100->200\n");
           }
           cnt--;
       }
    }
    else
    {
       //parent
       while(1)
       {
           printf("father, Pid: %d, Ppid: %d, g_val: %d, &g_val=%p\n",getpid(),getppid(),g_val,&g_val);
           sleep(1);
       }
    }
    
    return 0;
}
